#ifndef CHARDWAREFACADE_H
#define CHARDWAREFACADE_H

#include <QProgressBar>
#include <QThread>
#include <QWaitCondition>
#include "QAfarsekFileList.h"
#include "qextserialport.h"
#include "qextserialenumerator.h"

#include "CFileSystem.h"
#include "CHardwareParams.h"


//===================================================================
//
//      DEFINES AND MACROS
//
//===================================================================
#define MOUSSAVI_PRODUCT_ID     "MOUSSAVI"
#define ANIBIKE_PRODUCT_ID      "ANIBIKE"
#define VENDOR_ID               "DAVID.M"

#define WAIT_FOR_BYTES(ms)    { int timeOutTimer = (ms);                \
                                msleep(40);                             \
                                while (!serialPort->bytesAvailable ()   \
                                                &&timeOutTimer){        \
                                usleep(15000);                          \
                                timeOutTimer--;  }}

#define WAIT_FOR_BYTES_N(ms, b)    { int timeOutTimer = (ms);                   \
                                     while (serialPort->bytesAvailable()<(b)    \
                                                &&(timeOutTimer>0)){            \
                                     usleep(2000);                              \
                                     timeOutTimer--;  }}

enum {
    FOUND_NOTHING   = 0,
    FOUND_MOUSSAVI  = 1,
    FOUND_ANIBIKE   = 2
};

enum {
    ECHO_OFF        = 0,
    ECHO_ON         = 1,
    ECHO_UNKNOWN    = 2
};

typedef enum {
    HADWARE_FACADE_JOB_NO_JOB           = 0,
    HADWARE_FACADE_JOB_TEST_LEDS           ,
    HADWARE_FACADE_JOB_SYNCRONIZE        ,
    HADWARE_FACADE_JOB_LAST_JOB
} HADWARE_FACADE_JOB_EN;


class CHardwareFacadeJob
{
public:
    HADWARE_FACADE_JOB_EN       enJobID;
    CFileSystem                 *fs;
    QAfarsekFileList            *fileList;
};

//===================================================================
//
//      COMMANDS
//
//===================================================================
#define     CMD_IDN        "idn?:"
#define     CMD_REPA       "repa:"
#define     CMD_EON        "eon:"
#define     CMD_EOF        "eof:"
#define     CMD_START      "start_all:"
#define     CMD_STOP       "stop_all:"

//===================================================================
//
//      CHARDWAREFACADE
//
//===================================================================

class CFileSystem;


class CHardwareFacade : public QThread
{
    Q_OBJECT
public:
    explicit CHardwareFacade( QObject* parent = 0);
    //CHardwareFacade(QextPortInfo info, bool simulation = 0);
    CHardwareFacade(const CHardwareFacade& hardware);
    ~CHardwareFacade(void);
    void SetInitParameters(QextPortInfo info, bool simulation = 0);
    int CheckConnectionAndType ( void );
    void DeleteSerialPort ( void );
    void setDeviceNumber (int number);

    int ConnectDevice(void);
    void DisconnectDevice(void);
    void ResetDevice (void);
    bool IsConnected(void);
    CHardwareParams*  GetParameters(void);
    int GetFileSystemRaw(unsigned char* data, int *length);    // The data is a pointer to pointer
                                                                // It is automatically allocated here
    int SynchronizeFileSystem(CFileSystem *fs, QAfarsekFileList* fileList=NULL);

    int TransferFile (CFileSystem *fs, file_list_it_t& file);
    int TransferEntryTable (CFileSystem *fs);
    int WriteLedCalibrations ( int maxR, int maxG, int maxB );
    int ReadLedCalibrations  ( int *maxR, int *maxG, int *maxB );
    int TestLeds ( void );


private:
    int TransferSingleBlock( int blockNum,
                             unsigned char *data,
                             int length,
                             bool erase_unprotect = true,
                             QProgressBar* progress = NULL );

    int TransferSingleBlockCRC16( int blockNum,
                                  unsigned char *data,
                                  int length,
                                  int totalLength,
                                  bool erase_unprotect = true,
                                  bool post_protect = true,
                                  CFileSystem *fs = NULL );

    int ReadOutSingleBlock( int blockNum, unsigned char *data, QProgressBar* progress = NULL );

    int CommandAndCheck ( const char *data );        // sends string data and verifies "ok" response
    int SendDataCRC16 ( unsigned char *data, int length );
    void StringToLower ( char *str, int length = -1 );
    unsigned short crc16_update(unsigned short crc, unsigned char a);

    int SendMessageAndWait ( QString msg, QString eol, QString& retVal, int timeoutMS = 1000 );
    int GetIdentificationString ( QString& retVal, int timeoutMS = 1000 );
    int GetParametersString ( QString& retVal, int timeoutMS = 1000 );
    int StartAllCommand ( int timeoutMS = 1000 );
    int StopAllCommand ( int timeoutMS = 1000 );
    int EchoOnCommand ( int timeoutMS = 100 );
    int EchoOffCommand ( int timeoutMS = 100 );
    int LocateSubString( char* main, char* sub, int lengthMain, int lengthSub);

    int asyncSynchronizeFileSystem(CFileSystem *fs);
    int asyncTestLeds (int rowNum, int delay, int turnOff);
private:
    bool    m_Simulation;
    bool    m_ParametersValid;
    bool    m_FSValid;
    bool    m_Connected;
    int     m_EchoIsOn;
    int     m_deviceNumber;

    unsigned char       *m_FrameData;
    int                 m_CurrDataLength;

    int                 m_FoundSystemType;
    QextSerialPort      *serialPort;
    CHardwareParams     m_HWParams;
    QextPortInfo        m_info;


    // Worker thread parameters
    QMutex              m_mutex;
    QWaitCondition      m_condition;
    CHardwareFacadeJob  m_currentJob;
    bool                m_abortJob;
    bool                m_exitWorkerThread;
    bool                m_working;

protected:
    void run ();

signals:
    void requestUpdateProgressBar ( int fsAddress, int progress );
    void requestUpdateFileList (void);

public slots:
    void onFinishedRunning ( void );
};

#endif // CHARDWAREFACADE_H
